﻿using System;
using System.Collections;
using System.Data;
using System.Linq;
using System.Collections.Specialized;

namespace System.Collections.Generic
{
    /// <summary>
    /// 集合类的扩展方法
    /// </summary>
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    public static class CollectionExtensions
    {
        #region Add 添加
        /// <summary>
        ///  向集合中添加一个元素，但元素为非重复项时添加，返回是否添加成功
        /// 	Adds a value uniquely to to a collection and returns a value whether the value was added or not.
        /// </summary>
        /// <typeparam name = "T">The generic collection value type</typeparam>
        /// <param name = "collection">The collection.</param>
        /// <param name = "value">The value to be added.</param>
        /// <returns>Indicates whether the value was added or not</returns>
        /// <example>
        /// 	<code>
        /// 		list.AddUnique(1); // returns true;
        /// 		list.AddUnique(1); // returns false the second time;
        /// 	</code>
        /// </example>
        public static bool AddUnique<T>(this ICollection<T> collection, T value)
        {
            var alreadyHas = collection.Contains(value);
            if (!alreadyHas)
            {
                collection.Add(value);
            }
            return alreadyHas;
        }

        /// <summary>
        ///  向集合中插入一个集合，去掉重复项，返回非重复项个数
        /// 	Adds a range of value uniquely to a collection and returns the amount of values added.
        /// </summary>
        /// <typeparam name = "T">The generic collection value type.</typeparam>
        /// <param name = "collection">The collection.</param>
        /// <param name = "values">The values to be added.</param>
        /// <returns>The amount if values that were added.</returns>
        public static int AddRangeUnique<T>(this ICollection<T> collection, IEnumerable<T> values)
        {
            var count = 0;
            foreach (var value in values)
            {
                if (collection.AddUnique(value))
                    count++;
            }
            return count;
        }

        /// <summary>
        /// 向集合中添加不定长的参数数组
        /// Adds the specified items to the collection.
        /// </summary>
        /// <typeparam name="T">Type of the items in the collection.</typeparam>
        /// <param name="collection">The collection to add to.</param>
        /// <param name="items">The items to add.</param>
        public static int AddRangeUnique<T>(this ICollection<T> collection, params T[] items)
        {
            var count = 0;
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            foreach (var item in items)
            {
                if (collection.AddUnique(item))
                    count++;
            }
            return count;
        }

        /// <summary>
        /// 向集合中添加不定长的参数数组
        /// Adds the specified items to the collection.
        /// </summary>
        /// <typeparam name="T">Type of the items in the collection.</typeparam>
        /// <param name="collection">The collection to add to.</param>
        /// <param name="items">The items to add.</param>
        public static void AddRange<T>(this ICollection<T> collection, params T[] items)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            foreach (var item in items)
            {
                collection.Add(item);
            }
        }

        /// <summary>
        /// Adds the specified items to the collection.
        /// </summary>
        /// <typeparam name="T">Type of the items in the collection.</typeparam>
        /// <param name="collection">The collection to add to.</param>
        /// <param name="items">The items to add.</param>
        public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            foreach (var item in items)
            {
                collection.Add(item);
            }
        }

        #endregion AddRange

        #region
        ///<summary>
        ///	Remove an item from the collection with predicate
        ///</summary>
        ///<param name = "collection"></param>
        ///<param name = "predicate"></param>
        ///<typeparam name = "T"></typeparam>
        ///<exception cref = "ArgumentNullException"></exception>
        /// <remarks>
        /// 	Contributed by Michael T, http://about.me/MichaelTran
        /// 	Renamed by James Curran, to match corresponding HashSet.RemoveWhere()
        /// </remarks>
        public static void RemoveWhere<T>(this ICollection<T> collection, Predicate<T> predicate)
        {
            if (collection == null)
                throw new ArgumentNullException("collection");
     
            var deleteList = collection.Where(child => predicate(child)).ToList();
            deleteList.ForEach(t => collection.Remove(t));
        }
        #endregion

        #region 键值对

        /// <summary>
        /// 转换为字典
        /// </summary>
        /// <param name="collection"></param>
        /// <returns></returns>
        public static Dictionary<string, string> ToDictionary(this NameValueCollection collection)
        {
            var dic = new Dictionary<string, string>(collection == null ? 10 : collection.Count, StringComparer.OrdinalIgnoreCase);
            if (collection != null)
            {
                collection.AllKeys.ForEach(s => dic.Add(s, collection[s]));
            }

            return dic;
        }

        /// <summary>
        /// 从集合中获得指定的键值
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetValue(this NameValueCollection collection, string key)
        {
            return GetValue(collection, key, string.Empty);
        }

        /// <summary>
        /// 从集合中获得指定的键值
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static string GetValue(this NameValueCollection collection, string key, string defaultValue)
        {
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException("key");

            if (collection == null)
                return defaultValue;

            var e = collection[key];

            if (e == null)
                return defaultValue;

            return e;
        }

        #endregion NameValueCollection

        #region 列表

        //	/// <summary>
        //	/// 在一个序列中查找指定的项出现的位置
        //	/// </summary>
        //	/// <typeparam name="T"></typeparam>
        //	/// <param name="source"></param>
        //	/// <param name="target"></param>
        //	/// <param name="pos"></param>
        //	/// <param name="length"></param>
        //	/// <returns></returns>
        //	public static int IndexOf<T>(this IList<T> source, T target, int pos, int length)
        //where T : IEquatable<T>
        //	{
        //		for (int i = pos; i < pos + length; i++)
        //		{
        //			if (source[i].Equals(target))
        //				return i;
        //		}

        //		return -1;
        //	}

        //	/// <summary>
        //	/// 判断指定的序列是不是用特定的一部分值开始的
        //	/// </summary>
        //	/// <typeparam name="T">序列类型</typeparam>
        //	/// <param name="source">源序列</param>
        //	/// <param name="mark">要查找的目标</param>
        //	/// <returns></returns>
        //	public static int StartsWith<T>(this IList<T> source, T[] mark)
        //		where T : IEquatable<T>
        //	{
        //		return source.StartsWith(0, source.Count, mark);
        //	}

        //	/// <summary>
        //	/// 判断指定的序列是不是用特定的一部分值开始的
        //	/// </summary>
        //	/// <typeparam name="T">序列类型</typeparam>
        //	/// <param name="source">源序列</param>
        //	/// <param name="mark">要查找的目标</param>
        //	/// <param name="offset">开始查找的位置</param>
        //	/// <param name="length">要匹配的长度</param>
        //	/// <returns></returns>
        //	public static int StartsWith<T>(this IList<T> source, int offset, int length, T[] mark)
        //		where T : IEquatable<T>
        //	{
        //		int pos = offset;
        //		int endOffset = offset + length - 1;

        //		for (int i = 0; i < mark.Length; i++)
        //		{
        //			int checkPos = pos + i;

        //			if (checkPos > endOffset)
        //				return i;

        //			if (!source[checkPos].Equals(mark[i]))
        //				return -1;
        //		}

        //		return mark.Length;
        //	}

        //	public static bool EndsWith<T>(this IList<T> source, T[] mark)
        //		where T : IEquatable<T>
        //	{
        //		return source.EndsWith(0, source.Count, mark);
        //	}

        //	public static bool EndsWith<T>(this IList<T> source, int offset, int length, T[] mark)
        //		where T : IEquatable<T>
        //	{
        //		if (mark.Length > length)
        //			return false;

        //		for (int i = 0; i < Math.Min(length, mark.Length); i++)
        //		{
        //			if (!mark[i].Equals(source[offset + length - mark.Length + i]))
        //				return false;
        //		}

        //		return true;
        //	}

        //	public static T[] CloneRange<T>(this T[] source, int offset, int length)
        //	{
        //		T[] target = new T[length];
        //		Array.Copy(source, offset, target, 0, length);
        //		return target;
        //	}

        private static Random m_Random = new Random();

        /// <summary>
        /// 将一个数组内容随机打乱
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T[] RandomOrder<T>(this T[] source)
        {
            var n = source.Length / 2;

            for (var i = 0; i < n; i++)
            {
                var x = m_Random.Next(0, source.Length - 1);
                var y = m_Random.Next(0, source.Length - 1);

                if (x == y)
                    continue;

                var t = source[y];

                //swap position
                source[y] = source[x];
                source[x] = t;
            }

            return source;
        }

        /// <summary>
        /// 对泛型列表的数据进行分页
        /// </summary>
        /// <typeparam name="T">列表的类型</typeparam>
        /// <param name="obj">原始数据</param>
        /// <param name="pagesize">每页尺寸</param>
        /// <param name="pageindex">页码，引用型，当超过范围时会自动修正</param>
        /// <param name="totalpage">传出，表示当前共有多少页</param>
        /// <returns>分页后的结果</returns>
        public static T[] SplitPage<T>(this IList<T> obj, int pagesize, ref int pageindex, out int totalpage)
        {
            T[] result;
            int count;

            if (pagesize < 1)
                throw new System.ArgumentOutOfRangeException("pagesize", "每页尺寸不得小于1");

            totalpage = obj.Count.CeilingDivide(pagesize);
            if (pageindex < 1)
                pageindex = 1;
            else if (pageindex > totalpage)
                pageindex = totalpage;

            if (totalpage * pagesize > obj.Count)
                count = obj.Count - totalpage * (pagesize - 1);
            else
                count = pagesize;

            result = new T[count];

            int startIndex = pagesize * (pageindex - 1);
            for (int i = 0; i < count; i++)
            {
                result[i] = obj[i + startIndex];
            }

            return result;
        }

        /// <summary>
        /// 从一个列表中随机选择对象
        /// </summary>
        /// <typeparam name="T">队列数据类型</typeparam>
        /// <param name="list">列表</param>
        /// <param name="random">使用的随机种子。如果使用null，则会新建一个</param>
        /// <returns>获得的结果</returns>
        public static T RandomTake<T>(this List<T> list, Random random = null)
        {
            if (list == null || list.Count == 0)
                return default(T);

            return list[(random ?? new Random()).Next(list.Count)];
        }

        #endregion 列表

        #region 字典

        /// <summary>
        /// 查找一个有序列表中指定的键的索引
        /// </summary>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="list">列表</param>
        /// <param name="key">要查找的键</param>
        /// <returns>返回相应的索引；如果没找到，则返回 -1</returns>
        public static int GetIndex<TKey, TValue>(this SortedList<TKey, TValue> list, TKey key)
        {
            if (list == null)
                return -1;

            var idx = 0;
            foreach (var keyidx in list.Keys)
            {
                if (keyidx.Equals(key))
                    return idx;
                idx++;
            }

            return -1;
        }

        #endregion 字典
    }
}